#define DDCLLUA_CORE

#include "ddclmap.h"
#include "ddclthread.h"
#include "ddclservice.h"
#include "ddclmalloc.h"
#include "lua-ddcl.h"

#include "string.h"

static ddcl_Map * _map = NULL;
static ddcl_RWLock _lock;

static int
l_set (lua_State * L){
    size_t len;
    const char * name = luaL_checklstring(L, 1, &len);
    ddcl_Service h = luaL_checkinteger(L, 2);
    ddcl_wlock_rw(&_lock);
    ddcl_Service* v = ddcl_malloc(sizeof(ddcl_Service));
    *v = h;
    ddcl_put_map(_map, name, len, v);
    ddcl_wunlock_rw(&_lock);
    return 0;
}

static int
l_get (lua_State * L){
    size_t len;
    const char * name = luaL_checklstring(L, 1, &len);
    ddcl_Service* h;
    ddcl_rlock_rw(&_lock);
    int ret = ddcl_get_map(_map, name, len, (const void **)&h);
    ddcl_runlock_rw(&_lock);
    if(!ret){
        return 0;
    }
    lua_pushinteger(L, *h);
    return 1;
}

static int
l_del (lua_State * L){
    size_t len;
    const char * name = luaL_checklstring(L, 1, &len);
    ddcl_Service* h;
    ddcl_wlock_rw(&_lock);
    int ret = ddcl_get_map(_map, name, len, (const void **)&h);
    ddcl_del_map(_map, name, len);
    ddcl_wunlock_rw(&_lock);
    if(ret){ ddcl_free(h); }
    return 0;
}

static luaL_Reg _REG[] = {
    {NULL, NULL}
};

DDCLLUA int
luaopen_ddcl_named (lua_State * L){
    luaL_checkversion(L);
    DDLUA_NEWLIB(L, "ddcl.named", _REG);
    luapush_ddcl_named(L, -1);
    return 1;
}

DDCLLUA int
luapush_ddcl_named (lua_State * L, int i){
    if(!_map){
        _map = ddcl_new_map(0);
        ddcl_init_rw(&_lock);
    }
    lua_checkstack(L, 4);
    lua_pushvalue(L, i);
    DDLUA_PUSHFUNC(L, "set", l_set);
    DDLUA_PUSHFUNC(L, "get", l_get);
    DDLUA_PUSHFUNC(L, "del", l_del);
    lua_pop(L, 1);
    return 0;
}
